package com.thaiopensource.relaxng.output.dtd;

import java.util.HashMap;
import java.util.Map;

import com.thaiopensource.xml.util.WellKnownNamespaces;

public class Datatypes
{

  private static final Map <String, Info> xsdMap = new HashMap <String, Info> ();

  // exactly equivalent to DTD datatype of same name
  private static final int COMPATIBLE = 0x0;
  // closest to CDATA
  private static final int CDATA = 0x1;
  // closest to NMTOKEN
  private static final int NMTOKEN = 0x2;
  // closest to CDATA
  private static final int CDATA_EQUALITY = 0x4;
  // closest to CDATA
  private static final int TOKEN_EQUALITY = 0x8;
  // closest CDATA type is exact
  private static final int EXACT = 0x10;

  private static final Object [] others = { "",
                                           new Info ("string", CDATA | EXACT | CDATA_EQUALITY),
                                           "",
                                           new Info ("token", CDATA | EXACT | TOKEN_EQUALITY),
                                           WellKnownNamespaces.RELAX_NG_COMPATIBILITY_DATATYPES,
                                           new Info ("ID", COMPATIBLE | EXACT | TOKEN_EQUALITY),
                                           WellKnownNamespaces.RELAX_NG_COMPATIBILITY_DATATYPES,
                                           new Info ("IDREF", COMPATIBLE | EXACT | TOKEN_EQUALITY),
                                           WellKnownNamespaces.RELAX_NG_COMPATIBILITY_DATATYPES,
                                           new Info ("IDREFS", COMPATIBLE | EXACT | TOKEN_EQUALITY) };

  public final static class Info
  {
    private final String name;
    private final int flags;

    private Info (final String name, final int flags)
    {
      this.name = name;
      this.flags = flags;
    }

    public String closestType ()
    {
      switch (flags & 0x3)
      {
        case COMPATIBLE:
          return name;
        case NMTOKEN:
          return "NMTOKEN";
        default:
          return "CDATA";
      }
    }

    public boolean isExact ()
    {
      return (flags & EXACT) != 0;
    }

    public boolean usesTokenEquality ()
    {
      return (flags & TOKEN_EQUALITY) != 0;
    }

    public boolean usesCdataEquality ()
    {
      return (flags & CDATA_EQUALITY) != 0;
    }
  }

  public static Info getInfo (final String datatypeLibrary, final String localName)
  {
    if (datatypeLibrary.equals (WellKnownNamespaces.XML_SCHEMA_DATATYPES))
      return xsdMap.get (localName);
    for (int i = 0; i < others.length; i += 2)
      if (datatypeLibrary.equals (others[i]) && localName.equals (((Info) others[i + 1]).name))
        return (Info) others[i + 1];
    return null;
  }

  private static void xsd (final String name, final int flags)
  {
    xsdMap.put (name, new Info (name, flags));
  }

  static
  {
    xsd ("ENTITIES", COMPATIBLE | EXACT | TOKEN_EQUALITY);
    xsd ("ENTITY", COMPATIBLE | EXACT | TOKEN_EQUALITY);
    xsd ("ID", COMPATIBLE | EXACT | TOKEN_EQUALITY);
    xsd ("IDREF", COMPATIBLE | EXACT | TOKEN_EQUALITY);
    xsd ("IDREFS", COMPATIBLE | EXACT | TOKEN_EQUALITY);
    xsd ("NMTOKEN", COMPATIBLE | EXACT | TOKEN_EQUALITY);
    xsd ("NMTOKENS", COMPATIBLE | EXACT | TOKEN_EQUALITY);
    xsd ("NOTATION", NMTOKEN);
    xsd ("NCName", NMTOKEN);
    xsd ("QName", NMTOKEN);
    xsd ("anyURI", CDATA | CDATA_EQUALITY);
    xsd ("base64Binary", CDATA);
    xsd ("boolean", NMTOKEN);
    xsd ("byte", CDATA);
    xsd ("date", NMTOKEN);
    xsd ("dateTime", NMTOKEN);
    xsd ("decimal", CDATA);
    xsd ("duration", NMTOKEN);
    xsd ("gDay", NMTOKEN);
    xsd ("gMonth", NMTOKEN);
    xsd ("gMonthDay", NMTOKEN);
    xsd ("gYear", NMTOKEN);
    xsd ("gYearMonth", NMTOKEN);
    xsd ("hexBinary", NMTOKEN);
    xsd ("int", CDATA);
    xsd ("integer", CDATA);
    xsd ("language", CDATA); // XXX
    xsd ("long", CDATA);
    xsd ("negativeInteger", CDATA);
    xsd ("nonNegativeInteger", CDATA);
    xsd ("nonPositiveInteger", CDATA);
    xsd ("normalizedString", CDATA | EXACT | CDATA_EQUALITY);
    xsd ("positiveInteger", CDATA);
    xsd ("short", CDATA);
    xsd ("string", CDATA | EXACT | CDATA_EQUALITY);
    xsd ("time", NMTOKEN);
    xsd ("token", CDATA | EXACT | TOKEN_EQUALITY);
    xsd ("unsignedInt", CDATA);
    xsd ("unsignedLong", CDATA);
    xsd ("unsignedShort", CDATA);
  }
}
